#pragma once

#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>

struct ThreadData
{
    std::string _threadname;
    pthread_t _tid;
};

template<typename T>
class ThreadPool
{
public:
    static const int N = 10;

    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void Wake()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _q.size() == 0;
    }

    std::string getName(const pthread_t& tid)
    {
        for(auto td : _threads)
        {
            if(td._tid == tid)
            {
                return td._threadname;
            }
        }

        return "None";
    }

    static void* handler(void* argc)
    {
        ThreadPool<T>* t = static_cast<ThreadPool<T>*>(argc);
        // 检查有没有任务， 有处理任务， 没有就休眠
        while(1)
        {
            t->Lock();

            while(t->isEmpty())
            {
                t->Sleep();
            }

            // 拿到任务
            //T data = t->pop();
            T task = t->pop();
            task.run();
            //std::cout << "拿到了一个数据 : " + std::to_string(data) + "\n";
            std::cout << t->getName(pthread_self()) +  task.finishTask() + "\n";
            t->Unlock();
            usleep(10);
        }
    }
    
public:

    ThreadPool(int num = N)
        : _threads(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }


    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void start()
    {
        int n = _threads.size();
        for(int i = 0; i < n; i++)
        {
            _threads[i]._threadname = "thread_" + std::to_string(i + 1);
            pthread_create(&(_threads[i]._tid), nullptr, handler, this);
        }
    }

    void push(const T& in)
    {
        Lock();
        _q.push(in);
        Wake();
        Unlock();
    }

    T pop()
    {
        T t = _q.front();
        _q.pop();
        return t;
    }


private:
    std::vector<ThreadData> _threads;
    std::queue<T> _q;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

};
